/****************************************************************************
*
* Copyright (c) 2023  C*Core -   All Rights Reserved
*
* THIS SOFTWARE IS DISTRIBUTED "AS IS, " AND ALL WARRANTIES ARE DISCLAIMED,
* INCLUDING MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* PROJECT     : CCFC2011BC
* DESCRIPTION : CCFC2011BC edma low level drivers code
* HISTORY     : Initial version.
* @file     edma.c
* @version  1.1
* @date     2023 - 02 - 20
* @brief    Initial version.
*
*****************************************************************************/
#include "edma_lld.h"
#include "CCFC2011BC.h"
#include "intc_lld.h"
#include "sys.h"
#include "spi_lld.h"

#if (HAS_EDMA == TRUE)



/* ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  = */
/* Driver interrupt handlers.                                                */
/* ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  = */
/**
 * @brief   Configurations for the various EDMA channels.
 */
static const edma_channel_config_t *channels[EDMA_NCHANNELS];

/**
 * @brief   EDMA (channels 0..31) error interrupt.
 *
 * @isr
 */
static IRQ_HANDLER(EDMA_ERR_FLAG_31_0_HANDLER)
{
    edma_channel_t channel;
    uint32_t erl, esr = EDMA.ESR.R;

    IRQ_PROLOGUE();

    /* Scanning for errors.*/
    channel = 0;
    erl = EDMA.ERL.R;
  #if (EDMA_NCHANNELS > 32U)
    while ((erl != 0U) && (channel < 32U))
    {
  #else
    while ((erl != 0U) && (channel < EDMA_NCHANNELS))
    {
  #endif
      if ((erl & (1UL << (uint32_t)channel)) != 0U)
      {
        /* Error flag cleared.*/
        EDMA.CER.R = (uint8_t)channel;

        /* If the channel is not associated then the error is simply discarded
          else the error callback is invoked.*/
        if ((channels[channel] != NULL) &&
            (channels[channel]->dma_error_func != NULL))
        {
          channels[channel]->dma_error_func((channels[channel]->dma_param), esr);
        }
      }
      channel++;
      erl = EDMA.ERL.R;
    }

    IRQ_EPILOGUE();
}
/**
 * @brief  EDMA interrupt handler.
 *
 * @isr
 */
#if (SPI_DMA_MODE != SPI_DMA_NONE)
#if (SPI_DMA_MODE != SPI_DMA_RX_ONLY)

  /**
   * @brief   EDMA channel 0 interrupt.
   *
   * @isr
   */
static IRQ_HANDLER(EDMA_CH0_HANDLER)
  {
    IRQ_PROLOGUE();

    if (channels[0] == NULL)
    {
        EDMA_ERROR_HANDLER();
    }
    EDMA.CIRQR.R = 0;
    channels[0]->dma_func(channels[0]->dma_param);

    IRQ_EPILOGUE();
  }

  /**
   * @brief   EDMA channel 1 interrupt.
   *
   * @isr
   */
static IRQ_HANDLER(EDMA_CH1_HANDLER)
  {
    IRQ_PROLOGUE();

    if (channels[1] == NULL)
    {
        EDMA_ERROR_HANDLER();
    }
    EDMA.CIRQR.R = 1;
    channels[1]->dma_func(channels[1]->dma_param);

    IRQ_EPILOGUE();
  }
/**
 * @brief   EDMA channel 2 interrupt.
 *
 * @isr
 */
static IRQ_HANDLER(EDMA_CH2_HANDLER)
{
    IRQ_PROLOGUE();

    if (channels[2] == NULL)
    {
        EDMA_ERROR_HANDLER();
    }
    EDMA.CIRQR.R = 2;

    channels[2]->dma_func(channels[2]->dma_param);

    IRQ_EPILOGUE();
}

#endif
/**
 * @brief   EDMA channel 3 interrupt.
 *
 * @isr
 */
static IRQ_HANDLER(EDMA_CH3_HANDLER)
{
    IRQ_PROLOGUE();

    if (channels[3] == NULL)
    {
        EDMA_ERROR_HANDLER();
    }
    EDMA.CIRQR.R = 3;
    channels[3]->dma_func(channels[3]->dma_param);

    IRQ_EPILOGUE();
}
#endif

/**
 * @brief   EDMA channel 4 interrupt.
 *
 * @isr
 */
static IRQ_HANDLER(EDMA_CH4_HANDLER)
{
    IRQ_PROLOGUE();

    if (channels[4] == NULL)
    {
        EDMA_ERROR_HANDLER();
    }
    EDMA.CIRQR.R = 4;
    channels[4]->dma_func(channels[4]->dma_param);

    IRQ_EPILOGUE();
}

/**
 * @brief   EDMA channel 5 interrupt.
 *
 * @isr
 */
static IRQ_HANDLER(EDMA_CH5_HANDLER)
{
    IRQ_PROLOGUE();

    if (channels[5] == NULL)
    {
        EDMA_ERROR_HANDLER();
    }
    EDMA.CIRQR.R = 5;
    channels[4]->dma_func(channels[5]->dma_param);

    IRQ_EPILOGUE();
}

/**
 * @brief   EDMA channel 6 interrupt.
 *
 * @isr
 */
static IRQ_HANDLER(EDMA_CH6_HANDLER)
{
    IRQ_PROLOGUE();

    if (channels[6] == NULL)
    {
        EDMA_ERROR_HANDLER();
    }
    EDMA.CIRQR.R = 6;
    channels[6]->dma_func(channels[6]->dma_param);

    IRQ_EPILOGUE();
}

/**
 * @brief   EDMA channel 7 interrupt.
 *
 * @isr
 */
static IRQ_HANDLER(EDMA_CH7_HANDLER)
{
    IRQ_PROLOGUE();

    if (channels[7u] == NULL)
    {
        EDMA_ERROR_HANDLER();
    }
    EDMA.CIRQR.R = 7u;
    channels[7u]->dma_func(channels[7u]->dma_param);

    IRQ_EPILOGUE();
}

/**
 * @brief   EDMA channel 8 interrupt.
 *
 * @isr
 */
static IRQ_HANDLER(EDMA_CH8_HANDLER)
{
    IRQ_PROLOGUE();

    if (channels[8] == NULL)
    {
      EDMA_ERROR_HANDLER();
    }
    EDMA.CIRQR.R = 8;
    channels[8]->dma_func(channels[8]->dma_param);

    IRQ_EPILOGUE();
}

/**
 * @brief   EDMA channel 9 interrupt.
 *
 * @isr
 */
static IRQ_HANDLER(EDMA_CH9_HANDLER)
{
    IRQ_PROLOGUE();

    if (channels[9] == NULL)
    {
        EDMA_ERROR_HANDLER();
    }
    EDMA.CIRQR.R = 9;
    channels[9]->dma_func(channels[9]->dma_param);

    IRQ_EPILOGUE();
}

/**
 * @brief   EDMA channel 10 interrupt.
 *
 * @isr
 */
static IRQ_HANDLER(EDMA_CH10_HANDLER)
{
    IRQ_PROLOGUE();

    if (channels[10] == NULL)
    {
        EDMA_ERROR_HANDLER();
    }
    EDMA.CIRQR.R = 10;
    channels[10]->dma_func(channels[10]->dma_param);

    IRQ_EPILOGUE();
}

/**
 * @brief   EDMA channel 11 interrupt.
 *
 * @isr
 */
static IRQ_HANDLER(EDMA_CH11_HANDLER)
{
    IRQ_PROLOGUE();

    if (channels[11] == NULL)
    {
        EDMA_ERROR_HANDLER();
    }
    EDMA.CIRQR.R = 11;
    channels[11]->dma_func(channels[11]->dma_param);

    IRQ_EPILOGUE();
}

/**
 * @brief   EDMA channel 12 interrupt.
 *
 * @isr
 */
static IRQ_HANDLER(EDMA_CH12_HANDLER)
{
    IRQ_PROLOGUE();

    if (channels[12] == NULL)
    {
        EDMA_ERROR_HANDLER();
    }
    EDMA.CIRQR.R = 12;
    channels[12]->dma_func(channels[12]->dma_param);

    IRQ_EPILOGUE();
}

/**
 * @brief   EDMA channel 13 interrupt.
 *
 * @isr
 */
static IRQ_HANDLER(EDMA_CH13_HANDLER)
{
    IRQ_PROLOGUE();

    if (channels[13] == NULL)
    {
        EDMA_ERROR_HANDLER();
    }
    EDMA.CIRQR.R = 13;
    channels[13]->dma_func(channels[13]->dma_param);

    IRQ_EPILOGUE();
}

/**
 * @brief   EDMA channel 14 interrupt.
 *
 * @isr
 */
static IRQ_HANDLER(EDMA_CH14_HANDLER)
{
    IRQ_PROLOGUE();

    if (channels[14] == NULL)
    {
        EDMA_ERROR_HANDLER();
    }
    EDMA.CIRQR.R = 14;
    channels[14]->dma_func(channels[14]->dma_param);

    IRQ_EPILOGUE();
}

/**
 * @brief   EDMA channel 15 interrupt.
 *
 * @isr
 */
static IRQ_HANDLER(EDMA_CH15_HANDLER)
{
    IRQ_PROLOGUE();

    if (channels[15] == NULL)
    {
        EDMA_ERROR_HANDLER();
    }
    EDMA.CIRQR.R = 15;
    channels[15]->dma_func(channels[15]->dma_param);

    IRQ_EPILOGUE();
}

#if (SPI_DMA_MODE != SPI_DMA_NONE)


/*******************************************************************************
 * @brief      EdmaInit:EDMA driver initialization.
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
void EdmaInit(void)
{
    static const uint8_t g0[16] = {EDMA_GROUP0_PRIORITIES};
    uint8_t i;

    EDMA.CR.R    = EDMA_CR_SETTING;
    EDMA.ERQRL.R = 0x00000000U;
    EDMA.EEIRL.R = 0x00000000U;
    EDMA.IRQRL.R = 0xFFFFFFFFU;
    EDMA.ERL.R =   0xFFFFFFFFU;
  #if (EDMA_NCHANNELS > 32U)
    EDMA.ERQRH.R = 0x00000000U;
    EDMA.EEIRH.R = 0x00000000U;
    EDMA.IRQRH.R = 0xFFFFFFFFU;
    EDMA.ERH.R =   0xFFFFFFFFU;
  #endif
    /* Initializing all the channels with a different priority withing the
      channels group.*/
    for (i = 0; i < 16U; i++)
    {
        EDMA.CPR[i].R = g0[i];
    #if (EDMA_NCHANNELS > 16U)
        EDMA.CPR[i + 16U].R = g1[i];
    #endif
    #if (EDMA_NCHANNELS > 32U)
        EDMA.CPR[i + 32U].R = g2[i];
        EDMA.CPR[i + 48U].R = g3[i];
    #endif
    }

    /* Error interrupt source.*/
    INTC_InstallINTCInterruptHandler(EDMA_ERR_FLAG_31_0_HANDLER, EDMA_ERR_FLAG_31_0_NUMBER, EDMA_ERROR_IRQ_PRIO);  //  slian
    #if (EDMA_NCHANNELS > 32U)
    INTC_PSR(EDMA_ERR_FLAG_63_32_NUMBER) = EDMA_ERROR_IRQ_PRIO;
    #endif

#if defined(EDMA_MUX_PCTL)
    /* DMA MUX PCTL setup, only if required.*/
    SetPeripheralClockMode(EDMA_MUX_PCTL, EDMA_MUX_START_PCTL);
#endif
}

/*******************************************************************************
 * @brief      EDMA channel release.
 * @param[in]  ccfg channel configuration
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
void edmaChannelRelease(const edma_channel_config_t *ccfg)
{
    /* Enforcing a stop.*/
    EdmaChannelStop(ccfg->dma_channel);

    /* Clearing ISR sources for the channel.*/
    EDMA.CIRQR.R = (uint8_t)(ccfg->dma_channel);
    EDMA.CEEIR.R = (uint8_t)(ccfg->dma_channel);
    EDMA.CER.R   = (uint8_t)(ccfg->dma_channel);

    /* The channels is flagged as available.*/
    channels[ccfg->dma_channel] = NULL;
}

#endif

/** @} */
#if (SPI_DMA_MODE != SPI_DMA_NONE)
#if (EDMA_HAS_MUX == TRUE)

/*******************************************************************************
 * @brief      EDMA mux slot set.
 * @param[in]  ccfg      channel configuration
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void edmaSetMuxSlot(const edma_channel_config_t *ccfg)
{
#if (EDMA_NUM_OF_MUX > 1U)
    uint8_t i, chcfg = (uint8_t)ccfg->dma_channel;
    for (i = 0; i < ccfg->dma_mux; i++)
    {
        chcfg = chcfg - mux_ch_num[i];
    }
    /* Programming the MUX.*/
    /*lint - e9033*/
    DMAMUX(ccfg->dma_mux).CHCONFIG[chcfg].R = (uint8_t)(0x80U |
                                                            ccfg->dma_periph);
    /*lint + e9033*/
#else
    /* Programming the MUX.*/
    DMAMUX.CHCONFIG[ccfg->dma_channel].R = (uint8_t)(0x80u|ccfg->dma_periph);
#endif
}
#endif /* EDMA_HAS_MUX */

/*******************************************************************************
 * @brief      EDMA channel allocation.
 * @param[in]  ccfg      channel configuration
 * @param[out] None
 * @retval     The channel number. 
 *             EDMA_ERROR   if the channel cannot be allocated.
 * @notapi
 *******************************************************************************/
edma_channel_t EdmaChannelAllocate(const edma_channel_config_t *ccfg)
{
    /* If the channel is already taken then an error is returned.*/
    if (ccfg->dma_channel >= 16u)
    {
      return EDMA_ERROR;
    }
    if (channels[ccfg->dma_channel] != NULL)
    {
      return EDMA_ERROR;                          /* Already taken.           */
    }

#if (EDMA_HAS_MUX == TRUE)
    edmaSetMuxSlot(ccfg);
#endif

    /* Associating the configuration to the channel.*/
    channels[ccfg->dma_channel] = ccfg;

    /* If an error callback is defined then the error interrupt source is
      enabled for the channel.*/
    if (ccfg->dma_error_func != NULL)
    {
      EDMA.SEEIR.R = (uint8_t)ccfg->dma_channel;
    }

    /* Setting up IRQ priority for the selected channel.*/
        /* Method of accessing PSR DMA channels by incrementing channel index in the INTC_PSR
          macro not comply with MISRA C because it involves a cast on a composite expression.*/
          if (((uint32_t)EDMA_CH0_NUMBER + ccfg->dma_channel) == (uint32_t)EDMA_CH0_NUMBER)
          {
            INTC_InstallINTCInterruptHandler(EDMA_CH0_HANDLER, EDMA_CH0_NUMBER, ccfg->dma_irq_prio);  //  slian
          }
          if (((uint32_t)EDMA_CH0_NUMBER + ccfg->dma_channel )== (uint32_t)EDMA_CH1_NUMBER)
          {
            INTC_InstallINTCInterruptHandler(EDMA_CH1_HANDLER, EDMA_CH1_NUMBER, ccfg->dma_irq_prio);  //  slian
          }
          if (((uint32_t)EDMA_CH0_NUMBER + ccfg->dma_channel) == (uint32_t)EDMA_CH2_NUMBER)
          {
            INTC_InstallINTCInterruptHandler(EDMA_CH2_HANDLER, EDMA_CH2_NUMBER, ccfg->dma_irq_prio);  //  slian
          }

          if (((uint32_t)EDMA_CH0_NUMBER + ccfg->dma_channel) == (uint32_t)EDMA_CH3_NUMBER)
          {
            INTC_InstallINTCInterruptHandler(EDMA_CH3_HANDLER, EDMA_CH3_NUMBER, ccfg->dma_irq_prio);  //  slian
          }

          if (((uint32_t)EDMA_CH0_NUMBER + ccfg->dma_channel) == (uint32_t)EDMA_CH4_NUMBER)
          {
            INTC_InstallINTCInterruptHandler(EDMA_CH4_HANDLER, EDMA_CH4_NUMBER, ccfg->dma_irq_prio);  //  slian
          }

          if (((uint32_t)EDMA_CH0_NUMBER + ccfg->dma_channel )== (uint32_t)EDMA_CH5_NUMBER)
          {
            INTC_InstallINTCInterruptHandler(EDMA_CH5_HANDLER, EDMA_CH5_NUMBER, ccfg->dma_irq_prio);  //  slian
          }

          if (((uint32_t)EDMA_CH0_NUMBER + ccfg->dma_channel) == (uint32_t)EDMA_CH6_NUMBER)
          {
            INTC_InstallINTCInterruptHandler(EDMA_CH6_HANDLER, EDMA_CH6_NUMBER, ccfg->dma_irq_prio);  //  slian
          }
          if (((uint32_t)EDMA_CH0_NUMBER + ccfg->dma_channel) == (uint32_t)EDMA_CH7_NUMBER)
          {
            INTC_InstallINTCInterruptHandler(EDMA_CH7_HANDLER, EDMA_CH7_NUMBER, ccfg->dma_irq_prio);  //  slian
          }
          if (((uint32_t)EDMA_CH0_NUMBER + ccfg->dma_channel) == (uint32_t)EDMA_CH8_NUMBER)
          {
            INTC_InstallINTCInterruptHandler(EDMA_CH8_HANDLER, EDMA_CH8_NUMBER, ccfg->dma_irq_prio);  //  slian
          }
          if (((uint32_t)EDMA_CH0_NUMBER + ccfg->dma_channel) == (uint32_t)EDMA_CH9_NUMBER)
          {
            INTC_InstallINTCInterruptHandler(EDMA_CH9_HANDLER, EDMA_CH9_NUMBER, ccfg->dma_irq_prio);  //  slian
          }
          if (((uint32_t)EDMA_CH0_NUMBER + ccfg->dma_channel) == (uint32_t)EDMA_CH10_NUMBER)
          {
            INTC_InstallINTCInterruptHandler(EDMA_CH10_HANDLER, EDMA_CH10_NUMBER, ccfg->dma_irq_prio);  //  slian
          }
          if (((uint32_t)EDMA_CH0_NUMBER + ccfg->dma_channel) == (uint32_t)EDMA_CH11_NUMBER)
          {
            INTC_InstallINTCInterruptHandler(EDMA_CH11_HANDLER, EDMA_CH11_NUMBER, ccfg->dma_irq_prio);  //  slian
          }
          if (((uint32_t)EDMA_CH0_NUMBER + ccfg->dma_channel) == (uint32_t)EDMA_CH12_NUMBER)
          {
            INTC_InstallINTCInterruptHandler(EDMA_CH12_HANDLER, EDMA_CH12_NUMBER, ccfg->dma_irq_prio);  //  slian
          }
          if (((uint32_t)EDMA_CH0_NUMBER + ccfg->dma_channel) == (uint32_t)EDMA_CH13_NUMBER)
          {
            INTC_InstallINTCInterruptHandler(EDMA_CH13_HANDLER, EDMA_CH13_NUMBER, ccfg->dma_irq_prio);  //  slian
          }
          if (((uint32_t)EDMA_CH0_NUMBER + ccfg->dma_channel) == (uint32_t)EDMA_CH14_NUMBER)
          {
            INTC_InstallINTCInterruptHandler(EDMA_CH14_HANDLER, EDMA_CH14_NUMBER, ccfg->dma_irq_prio);  //  slian
          }
          if (((uint32_t)EDMA_CH0_NUMBER + ccfg->dma_channel) == (uint32_t)EDMA_CH15_NUMBER)
          {
            INTC_InstallINTCInterruptHandler(EDMA_CH15_HANDLER, EDMA_CH15_NUMBER, ccfg->dma_irq_prio);  //  slian
          }
  #if (EDMA_NCHANNELS > 16U)
    if ((ccfg->dma_channel > 15U) && (ccfg->dma_channel < 32U))
    {
      INTC_PSR(EDMA_CH16_NUMBER + ccfg->dma_channel - 16U) = ccfg->dma_irq_prio;
    }
  #endif
  #if (EDMA_NCHANNELS > 32U)
    else if (ccfg->dma_channel > 31U)
    {
    INTC_PSR(EDMA_CH32_NUMBER + ccfg->dma_channel - 32U) = ccfg->dma_irq_prio;
      /*lint + e9032 + e9033*/
    }
  #endif
    else
    {
        /*required by MISRA*/
    }
    return ccfg->dma_channel;
}
#endif

/*******************************************************************************
 * @brief      EEdmaChannelSetup_C
 * @param[in]  edma_channel_t n, 
               src,      
               dst,      
               soff,     
               doff,    
               ssize,      
               dsize,     
               nbytes,   
               iter,     
               slast,    
               dlast,     
               mode)        mode. EDMA_TCD_MODE_DREQ | EDMA_TCD_MODE_INT_END
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
void EdmaChannelSetup_C(
        edma_channel_t n,  /* channel.                 */
        vuint32_t src,      /* src.                     */
        vuint32_t dst,      /* dst.                     */
        vuint16_t soff,     /* soff, do not advance.    */
        vuint16_t doff,     /* doff, do not advance.    */
        uint8_t ssize,      /* ssize, 8 bits transfers. */
        uint8_t dsize,      /* dsize, 8 bits transfers. */
        uint32_t nbytes,    /* nbytes, always one.      */
        uint16_t iter,      /* iter.                    */
        int32_t slast,     /* slast.                   */
        int32_t dlast,     /* dlast.                   */
        uint16_t mode)      /* mode. EDMA_TCD_MODE_DREQ | EDMA_TCD_MODE_INT_END*/
{
    EDMA.TCD[n].SADDR = src;
    EDMA.TCD[n].SMOD  = 0;
    EDMA.TCD[n].SOFF  = (vint16_t)soff;
    EDMA.TCD[n].SSIZE = ssize;
    EDMA.TCD[n].SLAST = slast;

    EDMA.TCD[n].DADDR = dst;
    EDMA.TCD[n].DMOD  = 0;
    EDMA.TCD[n].DOFF  = (vint16_t)doff;
    EDMA.TCD[n].DSIZE = dsize;
    EDMA.TCD[n].DLAST_SGA = dlast;

    EDMA.TCD[n].NBYTES = nbytes ;                    /* Transfer 1 byte per minor loop */
    EDMA.TCD[n].BITER = iter;                       /* 12 minor loop iterations */
    EDMA.TCD[n].CITER = iter;                       /* Initialize current iteraction count */
    if ((mode & EDMA_TCD_MODE_DREQ) == EDMA_TCD_MODE_DREQ)
    {
        EDMA.TCD[n].D_REQ = 1;  /* Disable channel when major loop is done*/
    }
    EDMA.TCD[n].INT_HALF = 0;                     /* Interrupts are not used */
    if ((mode & EDMA_TCD_MODE_INT_END) == EDMA_TCD_MODE_INT_END)
    {
        EDMA.TCD[n].INT_MAJ = 1;
    }
    else
    {
    }
    EDMA.TCD[n].CITERE_LINK = 0;                  /* Linking is not used */
    EDMA.TCD[n].BITERE_LINK = 0;
    EDMA.TCD[n].MAJORE_LINK = 0;                  /* Dynamic program is not used */

    EDMA.TCD[n].E_SG = 0;
    EDMA.TCD[n].BWC = 0;                          /* Default bandwidth control - no stalls */
    EDMA.TCD[n].START = 0;                        /* Initialize status flags START, DONE, ACTIVE */
    EDMA.TCD[n].DONE = 0;
    EDMA.TCD[n].ACTIVE = 0;
}

/*******************************************************************************
 * @brief      DMAMUX_ChConfigEn
 * @param[in]  uint8_t ChNum, uint8_t ChSource
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
void DMAMUX_ChConfigEn(uint8_t ChNum, uint8_t ChSource)
{
    DMAMUX.CHCONFIG[ChNum].B.ENBL = 1U;
    DMAMUX.CHCONFIG[ChNum].B.SOURCE = ChSource;
}

/*******************************************************************************
 * @brief      EDMA_LLD_ConfigLoopTransfer
 * @param[in]  uint8_t channel, const edma_transfer_config_t *transferConfig
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
void EDMA_LLD_ConfigLoopTransfer(uint8_t channel, const edma_transfer_config_t *transferConfig)
{
    EDMA.TCD[channel].SADDR = transferConfig->srcAddr;                   /* source address */
    EDMA.TCD[channel].SMOD = (vuint16_t)transferConfig->srcModulo;                  /* source address modulo */
    EDMA.TCD[channel].SSIZE = (vuint16_t)transferConfig->srcTransferSize;           /* source transfer size */
    EDMA.TCD[channel].DMOD = (vuint16_t)transferConfig->destModulo;                 /* destination address modulo */
    EDMA.TCD[channel].DSIZE =(vuint16_t) transferConfig->destTransferSize;          /* destination transfer size */
    EDMA.TCD[channel].SOFF = transferConfig->srcOffset;                  /* signed source address offset */
    EDMA.TCD[channel].NBYTES = transferConfig->minorByteTransferCount;   /* inner byte count */
    /* last destination address adjustment, orscatter/gather address (if e_sg = 1) */
    EDMA.TCD[channel].SLAST = transferConfig->srcLastAddrAdjust;
    EDMA.TCD[channel].DADDR = transferConfig->destAddr;                  /* destination address */

    EDMA.TCD[channel].CITERE_LINK = transferConfig->loopTransferConfig->minorLoopChnLinkEnable;
    if (EDMA.TCD[channel].CITERE_LINK == 1u)
    {
        EDMA.TCD[channel].CITER = (transferConfig->loopTransferConfig->majorLoopIterationCount & 0x01ffu) | \
                                  ((uint32_t)transferConfig->loopTransferConfig->minorLoopChnLinkNumber << 9u);
    }
    else
    {
        EDMA.TCD[channel].CITER = transferConfig->loopTransferConfig->majorLoopIterationCount;
    }

    EDMA.TCD[channel].DOFF = transferConfig->destOffset;    /* signed destination address offset */
    EDMA.TCD[channel].DLAST_SGA = transferConfig->destLastAddrAdjust;

    EDMA.TCD[channel].BITERE_LINK = transferConfig->loopTransferConfig->majorLoopChnLinkEnable;
    if (EDMA.TCD[channel].BITERE_LINK == 1u)
    {
        EDMA.TCD[channel].BITER = (transferConfig->loopTransferConfig->majorLoopIterationCount & 0x01ffu) | \
                                  ((uint32_t)transferConfig->loopTransferConfig->majorLoopChnLinkNumber << 9u);
    }
    else
    {
        EDMA.TCD[channel].BITER = EDMA.TCD[channel].CITER;
    }

    EDMA.TCD[channel].BWC = 0;  /* bandwidth control */
    EDMA.TCD[channel].MAJORLINKCH = transferConfig->loopTransferConfig->majorLoopChnLinkNumber;    /* enable channel - to - channel link */
    EDMA.TCD[channel].MAJORE_LINK = transferConfig->loopTransferConfig->majorLoopChnLinkEnable;    /* enable channel - to - channel link */
    EDMA.TCD[channel].E_SG = transferConfig->scatterGatherEnable;      /* enable scatter/gather descriptor */
    EDMA.TCD[channel].D_REQ = transferConfig->hardwareRequestDisable;  /* disable ipd_req when done */
    EDMA.TCD[channel].INT_HALF = 0;                                    /* interrupt on citer = (biter >> 1) */
    EDMA.TCD[channel].INT_MAJ = transferConfig->interruptEnable;       /* interrupt on major loop completion */
    EDMA.TCD[channel].START = 0;                                       /* explicit channel start */
}

/*******************************************************************************
 * @brief      EDMA_LLD_ConfigLoopTransfer
 * @param[in]  uint8_t channel 
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
void EDMA_LLD_StartChannel(uint8_t channel)
{
    EDMA.SERQR.R = channel;
    while (EDMA.TCD[channel].ACTIVE == 1u)
    {
        ;
    }
}

/*******************************************************************************
 * @brief      EDMA_LLD_WaitDone
 * @param[in]  uint8_t channel 
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
void EDMA_LLD_WaitDone(uint8_t channel)
{
    while (EDMA.TCD[channel].DONE != 1u)
    {
        ;
    }
    EDMA.CDSBR.R = channel;
}

#endif/*HAS_EDMA*/
